#! /bin/bash

# Usage: run-test <build-path>

P=${1:-`pwd -P`}

DIM=(
    '32 32'
    '800 640'
    '1024 1024'
    '1920 1280'
)

COL=(
    'red       -M solid  --red 0xffff'
    'green     -M solid  --green 0xffff'
    'blue      -M solid  --blue 0xffff'
    'random-0  -M random --seed 0'
    'random-23 -M random --seed 23'
    'random-42 -M random --seed 42'
)

FMT=(
    gbrg
    bggr
    grbg
    rggb
)

DIM_FMT_COL=(
    '32 32 gbrg red_col0   -M column --column 2 --red 0xfffe'
    '32 32 gbrg red_col1   -M column --column 4 --red 0xfffe'
    '32 32 gbrg blue_col0  -M column --column 3 --blue 0xfffe'
    '32 32 gbrg blue_col1  -M column --column 5 --blue 0xfffe'
    '32 32 gbrg green_col0 -M column --column 2 --green 0xfffe'
    '32 32 gbrg green_col1 -M column --column 3 --green 0xfffe'
    '32 32 gbrg col4       -M column --column 6 --red 0x04 --blue 0x08 --green 0x10'
    "32 32 gbrg red_rnd    -M solid  --red   0xffff 4 5 0xfffe"
    "32 32 gbrg blue_rnd   -M solid  --blue  0xffff 5 6 0xfffe"
    "32 32 gbrg green_rnd0 -M solid  --green 0xffff 5 5 0xfffe"

#     "2048 2048 gbrg random_gbrg -M random --seed 0"
#     "2048 2048 bggr random_bggr -M random --seed 0"
#     "2048 2048 grbg random_grbg -M random --seed 0"
#     "2048 2048 rggb random_rggb -M random --seed 0"
)

EXACT_METHODS=(
    cc
    c-opt
    neon
)

ERROR_CNT=0
SUCCESS_CNT=0

############

tmp=`mktemp -d -t bayer-test.XXXXXX` || exit 1
trap "rm -rf $tmp" EXIT

function info {
    local fmt=$1
    shift

    printf "$fmt\n" "$@"
}

function run {
    if type -p libtool >/dev/null; then
	libtool --mode=execute ${DEBUG:-env} ${QEMU:-} "$@"
    else
	"$@"
    fi
}

function error {
    local fmt=$1
    shift

    printf "ERROR: $fmt\n" "$@"

    let ++ERROR_CNT
}

# <input> <width> <height> <fmt> <bpp> [<args>*]
function gen_image_bpp {
    local fname=$1
    local width=$2
    local height=$3
    local format=$4
    local bpp=$5

    shift 5

    info "Creating image '%s' (%dx%d, args '%s')" "$fname" "$width" "$height" "$*"

    ${QEMU:-} $P/testsuite/gen-image --width "$width" --height "$height" \
			   --format "$format" --bpp "$bpp" "$@" > "$tmp/$fname"

    echo "$bpp"    > "$tmp/$fname:bpp"
    echo "$width"  > "$tmp/$fname:width"
    echo "$height" > "$tmp/$fname:height"
    echo "$format" > "$tmp/$fname:format"
}

# <input> <width> <height> <fmt> [<args>*]
function gen_image {
    local fname=$1
    local width=$2
    local height=$3
    local format=$4

    shift 4

    gen_image_bpp "$fname" "$width" "$height" "$format" 8 "$@"
}

# Usage: read_pixel <fname> <x> <y> <width> <Bpp>
#                     $1     $2  $3   $4      $5
function read_pixel() {
    local fname=$1
    local pos=$[ ($3 * $4 + $2) * 4 * $5 ]

    set -- `dd if="$fname" bs=1 skip="$pos" count=$[ 4 * $5 ] status=none | od -A none -t x$5`

    res_R=$[ 0x$1 ]
    res_G=$[ 0x$2 ]
    res_B=$[ 0x$3 ]
    res_A=$[ 0x$4 ]
}

# Usage: special_check <fname> <conv-result> <width> <bpp>
function special_check() {
    local fname=$1
    local fresult=$2
    local width=$3
    local bpp=$4

    case $fname in
      mixed_*)
	    local exp_R=$[ 130 << (bpp - 8) ]
	    local exp_G=$[ 140 << (bpp - 8) ]
	    local exp_B=$[ 160 << (bpp - 8) ]
	    local exp_A=$[   0 << (bpp - 8) ]

	    info "  mixed check ($m)"
	    for ofs_x in -1 0 +1; do
		for ofs_y in -1 0 +1; do
		    read_pixel "$fresult" $[ 10 + ofs_x ] $[ 10 + ofs_y ] 160 $[ (bpp + 7) / 8 ]

		    test "$res_R" -eq "$exp_R" || error "bad R value ($res_R vs $exp_R)"
		    test "$res_G" -eq "$exp_G" || error "bad R value ($res_G vs $exp_G)"
		    test "$res_B" -eq "$exp_B" || error "bad R value ($res_B vs $exp_B)"
		    test "$res_A" -eq "$exp_A" || error "bad A value ($res_A vs $exp_A)"
		done
	    done

	    cp "$fresult" "$fresult".keep
	    ;;
    esac
}

# Usage: run_gen_test <name> <input> [<args>*]
function run_test {
    local test_name=$1
    local fname=$2
    local width
    local height
    local bpp
    local format
    local args

    shift 2

    args=( "$@" )

    read width  < "$tmp/$fname:width"
    read height < "$tmp/$fname:height"
    read bpp    < "$tmp/$fname:bpp"
    read format < "$tmp/$fname:format"

    info "Test '%s' on '%s' (%dx%d@%d)" "$test_name" "$fname" "$width" "$height" "$bpp"

    local out=$tmp/$fname:conv:

    rm -f "$out"*

    local m
    for m in "${EXACT_METHODS[@]}"; do
	eval set -- $m

	local method=$1

	run bayer2rgb --width "$width" --height "$height" --input-bpp "$bpp" \
	    --method "$method" --input-format="$format" --silent \
	    "${args[@]}" "$tmp/$fname" "${out}${method}"

	special_check "$fname" "${out}${method}" "$width" 8
    done

    local f
    local ref_img=
    for f in "${out}"*; do
	case $f in
	  *:neon)
		# TODO: ignore neon for now; it always differs at the
		# border regions Remove this branch when we have a
		# 'cmp' which allows to compare an inner window of the
		# image.
		#
		# Some correctness of NEON conversion is checked by
		# the 'mixed' special test.
		continue
		;;
	esac

	if test -z "$ref_img"; then
	    ref_img=$f
	    continue
	fi

	cmp -l "$ref_img" "$f" >&2 || error "'$ref_img' and '$f' differ"
    done

    rm -f "$out"*
}

set -e
shopt -s nullglob

images=()
for dim in "${DIM[@]}"; do
    eval set -- $dim

    w=$1
    h=$2

    for col in "${COL[@]}"; do
	eval set -- $col
	base=$1
	shift

	args=( $@ )

	for fmt in "${FMT[@]}"; do
	    img=${base}_${fmt}_${w}x${h}

	    gen_image "$img" "$w" "$h" "$fmt" "${args[@]}"
	    images+=( $img )
	done
    done
done

for dim in "${DIM_FMT_COL[@]}"; do
    eval set -- $dim

    w=$1
    h=$2
    fmt=$3
    base=$4

    shift 4

    args=( $@ )
    img=${base}_${fmt}_${w}x${h}

    gen_image "$img" "$w" "$h" "$fmt" "${args[@]}"
    images+=( $img )
done

for fmt in "${FMT[@]}"; do
    for b in 8 10 12 16; do
	img=mixed_${fmt}@${b}_160x160

	gen_image_bpp "$img" "160" "160" "$fmt" "$b" \
		  -M solid \
		  --red   $[ 130 << (b - 8) ] \
		  --green $[ 140 << (b - 8) ] \
		  --blue  $[ 160 << (b - 8) ]
	set +x

	images+=( $img )
    done
done

for img in "${images[@]}"; do
    run_test "simple" "$img" --quality -all
    run_test "round2" "$img" --quality +round2
    run_test "round4" "$img" --quality +round4
    run_test "round"  "$img" --quality +round
done

test 0 -eq "$ERROR_CNT"
